import numpy as np
import matplotlib.pyplot as plt

def M_M_1(lambda_rate, mu_rate, unit_time):
    """
    模拟MM1排队模型
    :param lambda_rate: 顾客到达率
    :param mu_rate: 服务员服务率
    :param unit_time: 单位时间
    :return: 平均队长，平均等待时间，到达时间，服务时间，离开时间，等待时间
    """
    team_length_history = []  # 记录每个时间点的队伍长度
    arrival_times = []  # 到达时间
    service_times = []  # 服务时间
    departure_times = []  # 离开时间
    wait_times = []  # 等待时间
    now_time = 0  # 当前时间
    busy = False  # 服务员是否忙碌
    team_length = 0  # 当前队伍长度

    while now_time <= unit_time:
        if not busy:
            # 如果有顾客到达
            if team_length == 0:
                next_arrival_time = np.random.exponential(1 / lambda_rate)# 顾客到达的时间间隔服从指数分布
                arrival_time = now_time + next_arrival_time
                arrival_times.append(arrival_time)
                now_time = arrival_time
                team_length += 1
                team_length_history.append(team_length)
            else:
                # 开始服务
                service_time = np.random.exponential(1 / mu_rate)
                service_times.append(service_time)
                departure_time = now_time + service_time
                departure_times.append(departure_time)
                busy = True
                now_time = departure_time
                wait_time = now_time - arrival_times.pop(0)
                wait_times.append(wait_time)
                team_length -= 1
                team_length_history.append(team_length)
        else:
            # 服务员忙碌，新顾客到达
            next_arrival_time = np.random.exponential(1 / lambda_rate)
            arrival_time = now_time + next_arrival_time
            arrival_times.append(arrival_time)
            if arrival_time < now_time:  # 防止时间倒流
                arrival_time = now_time
            team_length += 1
            team_length_history.append(team_length)

            # 检查是否有顾客完成服务
            if now_time >= departure_times[-1]:
                busy = False
                now_time = departure_times.pop(0)
                wait_time = now_time - arrival_times.pop(0)
                wait_times.append(wait_time)
                team_length -= 1
                team_length_history.append(team_length)

    # 计算平均队长和平均等待时间
    # 服务强度
    p_service = lambda_rate/mu_rate
    avg_team_length = p_service/(1-p_service)
    avg_wait_time = p_service/((1-p_service)*mu_rate)

    return {
        'avg_team_length': avg_team_length,
        'avg_wait_time': avg_wait_time,
        'arrival_times': arrival_times,
        'service_times': service_times,  # 注意：这里service_times并没有记录每个顾客的独立服务时间
        'departure_times': departure_times,
        'wait_times': wait_times
    }

# 设置参数
lambda_rate = 5  # 顾客到达率
mu_rate = 15     # 服务率
unit_time = 600  # 单位时间

# 运行模拟
result = M_M_1(lambda_rate, mu_rate, unit_time)
# 输出结果
print(f"平均队长：{result['avg_team_length']}")
print(f"平均等待时间：{result['avg_wait_time']}")

# 绘制等待时间分布图
plt.hist(result['wait_times'], bins=50, edgecolor='black')
plt.title('Waiting time distribution')
plt.xlabel('Waiting time')
plt.ylabel('frequency')
plt.show()